; Disassembly of the file "z:\ramdisk\home\knoppix\none\2716 BOOT 80K EPROM green CoBra.bin" ; ; CPU Type: Z80 ; ; Created with dZ80 2.0 ; ; on Saturday, 08 of September 2012 at 07:37 PM ; ; Lines containing direct values of video addresses have been marked as *n* where n is a number ; Proper modification of these lines can make the graphic logo work if video RAM is located ; at a different address than C000. In total I found 58 such lines. ; ; Also lines that must to be modified for this code to run relocated have been marked with ---@@@ ; ; ############################## START ROUTINE #################################### ; 0000 3E83 LD A,$83 ; bit 7 = "1" 0002 ED4F LD R,A ; u36/5 kept at "1" after NPOR="0", so the computer stays in the startup hw config 0004 3173FD LD SP,$FD73 ; set stack at FD73 0007 2100C0 LD HL,$C000 ; *0* C000 is the start addr for video mem in startup hw configuration (C0->40 @ 0009) 000A 1101C0 LD DE,$C001 ; *1* C001 is the start addr+1 for video mem in startup hw configuration (C0->40 @ 000C) 000D 01FF1A LD BC,$1AFF ; 1AFF+1 is the standard total size of Spectrum video memory 0010 3600 LD (HL),$00 ; this will fill up all video memory with zeros when the LDIR below executes 0012 EDB0 LDIR 0014 210000 LD HL,$0000 ; start address of this BOOT EPROM code ---@@@(1)0016:00->10 0017 110080 LD DE,$8000 ; start address of DRAM#0 in the startup config 001A 010008 LD BC,$0800 ; 0800h (2K) is the length of this BOOT EPROM code 001D EDB0 LDIR ; entire BOOT EPROM code is copied from EPROM into DRAM#0 001F 3E03 LD A,$03 ; channel control word for Z80CTC, used in the next 4 instructions: ; ; (Disable Interrupt, Timer mode, Prescaler=16, CLK/TRG Falling Edge, ; ; Auto Trigger, No Time Const. Follows, Reset Channel) 0021 D3E3 OUT ($E3),A ; reset CTC channel 0 0023 D3EB OUT ($EB),A ; reset CTC channel 1 0025 D3F3 OUT ($F3),A ; reset CTC channel 2 0027 D3FB OUT ($FB),A ; reset CTC channel 3 0029 AF XOR A ; set A register to "00" 002A D3FD OUT ($FD),A ; write "00" to 8272 Data Register (invalid command, places 8272 in standby) 002C 3E92 LD A,$92 ; control word for 8255: Mode Set flag=active, ; ; Group A: Select Mode 0, ; ; Port A set to Input mode, ; ; Port C (upper half) set to Output Mode, ; ; Group B: Select Mode 0, ; ; Port B set to Input Mode, ; ; Port C (lower half) set to Output Mode 002E D3DF OUT ($DF),A ; write control word to 8255 0030 D3DF OUT ($DF),A ; write control word to 8255 (again !?) 0032 3E40 LD A,$40 0034 D3FE OUT ($FE),A ; write 40 to port C of 8255 ; ; (set border to black, set signal "SO" to 0, set signal "O5" to 0, ; ; set signal "O6" to 1 to allow access to video memory in the hw startup config) 0036 181E JR $0056 ;###################### START ROUTINE CONTINUES AT 0056 ######################### ; ; ############################## BASIC CONFIGURATION ############################## ; 0038 210040 LD HL,$4000 ; 4000 is the start addr of BASIC EPROM in the startup hw config 003B 110080 LD DE,$8000 ; 8000 is the start addr of DRAM#0 in the startup hw config 003E 010040 LD BC,$4000 ; 4000 is the length of the SPECTRUM BASIC code (16 KB) 0041 EDB0 LDIR ; copy SPECTRUM BASIC code into DRAM#0 0043 D9 EXX ; (after EXX, HL contains 0000, see line 07F4) 0044 3E03 LD A,$03 ; SAME AS ] 0046 D3E3 OUT ($E3),A ; ] 0048 D3EB OUT ($EB),A ; 001F ] 004A D3F3 OUT ($F3),A ; ] 004C D3FB OUT ($FB),A ; to ] 004E AF XOR A ; ] 004F D3FD OUT ($FD),A ; 002A ] 0051 D3FE OUT ($FE),A ; write 03 to port C of 8255 <--- <--- <--- <--- <--- <--- <--- <--- <--- <--- <--- <--- <--| ; ; (set border to white, set signal "SO" to 0, set signal "O5" to 0, | ; ; set signal "O6" to 0) | 0053 ED4F LD R,A ; set bit 7 of R to 0, prepare for BASIC hardware configuration | 0055 E9 JP (HL) ; change hardware configuration with a jump to (HL) | ; | ; ############################# END OF BASIC CONFIGURATION ######################## | ; | ; ; ###################### START ROUTINE CONTINUED ################################ | 0056 3EFE LD A,$FE ; upper half of address bus at I/O time in next instruction (test keyboard row KA8) | 0058 DBFE IN A,($FE) ; read port A of 8255 | 005A CB6F BIT 5,A ; keyboard test for CTRL key (test keyboard column K5) | 005C 2033 JR NZ,$0091 ; jump to 0091 if CTRL is not pressed | 005E AF XOR A ; set A to "00" (upper half of address bus at I/O time in next instruction) <--- <--- <-| | 005F DBFE IN A,($FE) ; read port A of 8255 (test keyboard, all rows) | | 0061 F640 OR $40 ; set bit 6 | | 0063 EE20 XOR $20 ; invert bit 5 | | 0065 D3FE OUT ($FE),A ; write result to port C of 8255 (set "O6" to 1, "O5" to 1 - since CTRL is pressed) | | 0067 21AA55 LD HL,$55AA ; | | 006A 225515 LD ($1555),HL ; | | 006D 22CC4C LD ($4CCC),HL ; | | 0070 220F8F LD ($8F0F),HL ; | | 0073 22FFC0 LD ($C0FF),HL ; | | 0076 2A5515 LD HL,($1555) ; | | 0079 2ACC4C LD HL,($4CCC) ; | | 007C 2A0F8F LD HL,($8F0F) ; | | 007F 2AFFC0 LD HL,($C0FF) ; | | 0082 E603 AND $03 ; test bits 0 and 1 (keys "A" and "S") | | 0084 20D8 JR NZ,$005E ; if they are both 1 (keys not pressed), jump back to 005E ---> ---> ---> ---> ---> --->| | 0086 DBFE IN A,($FE) ; read port A of 8255 | 0088 E640 AND $40 ; test bit 6 (Tape Input) | 008A 215E00 LD HL,$005E ; set jump address in new config to 005E | 008D 28C2 JR Z,$0051 ; if Tape Input=0 jump to 0051 ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> ---->| 008F 18C0 JR $0051 ; jump to 0051 anyway ; ; ######## COBRA GRAPHIC LOGO ########### ; 0091 2100D9 LD HL,$D900 ; *2* video attr start addr for 2nd third of video RAM in startup hw cfg (D9->59 @ 0093) 0094 0608 LD B,$08 0096 C5 PUSH BC 0097 01050C LD BC,$0C05 ; write "05" as color attribute 009A 71 LD (HL),C ; for the first 12 characters 009B 23 INC HL ; of the middle third in the 009C 10FC DJNZ $009A ; Spectrum screen (INK=cyan, PAPER=black) 009E 010314 LD BC,$1403 ; write "03" as color attribute 00A1 71 LD (HL),C ; for the next 20 characters 00A2 23 INC HL ; (INK==white, PAPER=black) 00A3 10FC DJNZ $00A1 ; so in total 32 characters (one line) 00A5 C1 POP BC 00A6 10EE DJNZ $0096 ; repeat the above 7 times,(all 8 lines in the middle third of screen) 00A8 D9 EXX 00A9 218801 LD HL,$0188 ; HL' used as pointer to data block start address (0188) ---@@@(2)00AB:01->11 00AC D9 EXX 00AD 21B9CB LD HL,$CBB9 ; *3* address within serial video RAM, middle third of screen (CB->4B @ 00AF) 00B0 11FE01 LD DE,$01FE ; data to be written in there 00B3 3E04 LD A,$04 00B5 0609 LD B,$09 00B7 C5 PUSH BC ; <--- <--- <--- <--- <--- <--- <--- <--- <--- <--- 00B8 47 LD B,A ; | 00B9 72 LD (HL),D ; write "01" at CBB9 <--- <--- <- <--- <-| | 00BA 23 INC HL ; | | | 00BB 73 LD (HL),E ; write "FE" at CBBA | | | 00BC D9 EXX ; | | | 00BD 7E LD A,(HL) ; read first byte of data (FF) | | | 00BE 23 INC HL ; increment pointer (HL'=0189) | | | 00BF D9 EXX ; | | | 00C0 4F LD C,A ; C = data byte | | | 00C1 85 ADD A,L ; A = data byte + L = B9 + CY | | | 00C2 6F LD L,A ; L = data byte + L | | | 00C3 3001 JR NC,$00C6 ; | | | 00C5 24 INC H ; H=CB+1=CC | | | 00C6 10F1 DJNZ $00B9 ; ---> ---> ---> ---> ---> --->>> | | 00C8 41 LD B,C ; | | 00C9 D9 EXX ; | | 00CA 5E LD E,(HL) ; Read 2 bytes | | 00CB 23 INC HL ; of data into | | 00CC 56 LD D,(HL) ; DE' register. | | 00CD 23 INC HL ; Increment pointer | | 00CE D5 PUSH DE ; | | 00CF D9 EXX ; | | 00D0 E1 POP HL ; HL = 2 data bytes | | 00D1 CB23 SLA E ; | | 00D3 CB12 RL D ; | | 00D5 30E2 JR NC,$00B9 ; ---> ---> ---> ---> ---> ---> ---> --->> | 00D7 CB1A RR D ; | 00D9 CB1B RR E ; | 00DB 16FF LD D,$FF ; | 00DD CB22 SLA D ; <---- | 00DF CB13 RL E ; | | 00E1 38FA JR C,$00DD ; ----> | 00E3 7A LD A,D ; | 00E4 2F CPL ; | 00E5 57 LD D,A ; | 00E6 1EFF LD E,$FF ; | 00E8 79 LD A,C ; | 00E9 C1 POP BC ; | 00EA 10CB DJNZ $00B7 ; ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> 00EC 5D LD E,L 00ED 54 LD D,H 00EE D9 EXX 00EF E5 PUSH HL 00F0 D9 EXX 00F1 E1 POP HL 00F2 060B LD B,$0B 00F4 C5 PUSH BC ; <--- <--- 00F5 47 LD B,A ; | 00F6 7E LD A,(HL) ; | 00F7 23 INC HL ; | 00F8 12 LD (DE),A ; <---- | 00F9 13 INC DE ; | | 00FA 10FC DJNZ $00F8 ; ----> | 00FC 7E LD A,(HL) ; | 00FD 23 INC HL ; | 00FE 5E LD E,(HL) ; | 00FF 23 INC HL ; | 0100 56 LD D,(HL) ; | 0101 23 INC HL ; | 0102 C1 POP BC ; | 0103 10EF DJNZ $00F4 ; ---> ---> 0105 21E003 LD HL,$03E0 ; addr of color attr for color pattern under logo (within data block) ---@@@(3)0107:03->13 0108 118CDA LD DE,$DA8C ; *4* addr of color attr for color pattern under logo (within video mem) (DA->5A @ 010A) 010B 010800 LD BC,$0008 ; length of color pattern under logo 010E EDB0 LDIR 0110 1607 LD D,$07 ; ######### BEGINNING OF ONE SCREEN CYCLE (KBD READ + SCROLL LEFT) ######### 0112 010000 LD BC,$0000 0115 3E78 LD A,$78 ; keyboard test, rows KA15 ("B" key), KA10 ("W" key), KA9 ("D" key), KA8 ("C" key) 0117 DBFE IN A,($FE) 0119 1F RRA 011A 1F RRA 011B D2F407 JP NC,$07F4 ; if "W" pressed, jump to OPUS loading routine ---@@@(4)011D:07->17 011E 1F RRA 011F D25205 JP NC,$0552 ; if "D" pressed, jump to CP/M loading routine ---@@@(5)0121:05->15 0122 1F RRA 0123 D23705 JP NC,$0537 ; if "C" pressed, jump to tape loading routine ---@@@(6)0125:05->15 0126 1F RRA 0127 D2F007 JP NC,$07F0 ; if "B" pressed, jump to BASIC loading routine ---@@@(7)0129:07->17 012A 1F RRA 012B D29704 JP NC,$0497 ; if "F4" or "CTRL" pressed, jump to checksum routine ---@@@(8)012D:04->14 012E 10E5 DJNZ $0115 ; cycle the above 256 times 0130 0D DEC C 0131 20E2 JR NZ,$0115 ; cycle the above 256 times (65536 times total) 0133 15 DEC D 0134 20DF JR NZ,$0115 ; cycle the above 7 times (458752 times total) 0136 0620 LD B,$20 0138 C5 PUSH BC ; BC=2000 0139 CD5901 CALL $0159 ; call SERIAL VIDEO GRAPHIC SCROLL LEFT 4 PIXELS ---@@@(9)013B:01->11 013C 2101D9 LD HL,$D901 ; *5* video attr start addr for 2nd third of video RAM in startup hw cfg (D9->59 @ 013E) 013F 0608 LD B,$08 ; ######## 00D5-00E7 mid screen attribute scroll left 1 char ######## 0141 C5 PUSH BC ; BC=0800 (B=08 used as row counter) <--- <--- <--- <--- <---| 0142 011F00 LD BC,$001F ; screen width in chars minus 1 | 0145 54 LD D,H ; | 0146 5D LD E,L ; DE=D901 | 0147 1D DEC E ; DE=D900 (start of row 1 (of 8) of attr's for middle third of screen) 0148 1A LD A,(DE) ; copy the first attr byte on the row | 0149 EDB0 LDIR ; shift 31 attribute bytes left, first byte overwritten | 014B 12 LD (DE),A ; save the former first byte into the last on the row | 014C 2C INC L ; HL now points to first char on next row | 014D 1C INC E ; DE now points to last char on row | 014E C1 POP BC ; POP back the row counter | 014F 10F0 DJNZ $0141 ; ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> ->| ######## 0151 CD5901 CALL $0159 ; call SERIAL VIDEO GRAPHIC SCROLL LEFT 4 PIXELS ---@@@(10)0153:01->11 0154 C1 POP BC 0155 10E1 DJNZ $0138 0157 18B7 JR $0110 ; ###### END COBRA GRAPHIC LOGO ROUTINE ######### 0159 0604 LD B,$04 ; ######## SERIAL VIDEO GRAPHIC SCROLL LEFT 4 PIXELS ######## 015B C5 PUSH BC 015C 21FFCF LD HL,$CFFF ; *6* address within video memory (CF->4F @ 015E) 015F 0608 LD B,$08 0161 C5 PUSH BC 0162 0608 LD B,$08 0164 C5 PUSH BC 0165 54 LD D,H 0166 5D LD E,L 0167 0620 LD B,$20 0169 37 SCF 016A CB16 RL (HL) 016C 2B DEC HL 016D 10FB DJNZ $016A 016F 3803 JR C,$0174 0171 1A LD A,(DE) 0172 3D DEC A 0173 12 LD (DE),A 0174 C1 POP BC 0175 B7 OR A 0176 11E000 LD DE,$00E0 0179 ED52 SBC HL,DE 017B 10E7 DJNZ $0164 017D 01E007 LD BC,$07E0 0180 09 ADD HL,BC 0181 C1 POP BC 0182 10DD DJNZ $0161 0184 C1 POP BC 0185 10D4 DJNZ $015B 0187 C9 RET ; ######## SERIAL VIDEO GRAPHIC SCROLL LEFT 4 PIXELS END ############# 0188 FF DB $FF ; ############## GRAPHIC DATA BLOCK ################ 0189 E0 DB $E0 018A FF DB $FF 018B 1F DB $1F 018C B1 DB $B1 018D C8 DB $C8 ; *7* (C8->48) 018E 45 DB $45 018F B9 DB $B9 0190 22 DB $22 0191 02 DB $02 0192 1F DB $1F 0193 A2 DB $A2 0194 16 DB $16 0195 22 DB $22 0196 02 DB $02 0197 1F DB $1F 0198 A2 DB $A2 0199 16 DB $16 019A 25 DB $25 019B 15 DB $15 019C 09 DB $09 019D 75 DB $75 019E 43 DB $43 019F 25 DB $25 01A0 BC DB $BC 01A1 02 DB $02 01A2 19 DB $19 01A3 25 DB $25 01A4 BC DB $BC 01A5 02 DB $02 01A6 19 DB $19 01A7 07 DB $07 01A8 1D DB $1D 01A9 D9 DB $D9 01AA 07 DB $07 01AB 1D DB $1D 01AC 0C DB $0C 01AD 9A DB $9A 01AE C8 DB $C8 ; *8* (C8->48) 01AF 07 DB $07 01B0 A5 DB $A5 01B1 90 DB $90 01B2 FF DB $FF 01B3 88 DB $88 01B4 FF DB $FF 01B5 E5 DB $E5 01B6 FF DB $FF 01B7 FF DB $FF 01B8 31 DB $31 01B9 07 DB $07 01BA 0C DB $0C 01BB 82 DB $82 01BC C8 DB $C8 ; *9* (C8->48) 01BD FF DB $FF 01BE FF DB $FF 01BF FF DB $FF 01C0 6D DB $6D 01C1 7F DB $7F 01C2 09 DB $09 01C3 07 DB $07 01C4 F7 DB $F7 01C5 07 DB $07 01C6 DF DB $DF 01C7 FF DB $FF 01C8 09 DB $09 01C9 CC DB $CC 01CA C8 DB $C8 ; *10* (C8->48) 01CB 7B DB $7B 01CC 92 DB $92 01CD FF DB $FF 01CE FF DB $FF 01CF EB DB $EB 01D0 FF DB $FF 01D1 FF DB $FF 01D2 C4 DB $C4 01D3 10 DB $10 01D4 AF DB $AF 01D5 C8 DB $C8 ; *11* (C8->48) 01D6 FC DB $FC 01D7 02 DB $02 01D8 FC DB $FC 01D9 02 DB $02 01DA FC DB $FC 01DB 02 DB $02 01DC FC DB $FC 01DD 02 DB $02 01DE FC DB $FC 01DF 02 DB $02 01E0 FC DB $FC 01E1 02 DB $02 01E2 0B DB $0B 01E3 F3 DB $F3 01E4 0B DB $0B 01E5 06 DB $06 01E6 87 DB $87 01E7 C8 DB $C8 ; *12* (C8->48) 01E8 C0 DB $C0 01E9 FF DB $FF 01EA FF DB $FF 01EB 72 DB $72 01EC FF DB $FF 01ED 0B DB $0B 01EE 46 DB $46 01EF C8 DB $C8 ; *13* (C8->48) 01F0 74 DB $74 01F1 6E DB $6E 01F2 3D DB $3D 01F3 52 DB $52 01F4 8E DB $8E 01F5 9F DB $9F 01F6 FE DB $FE 01F7 DD DB $DD 01F8 FF DB $FF 01F9 82 DB $82 01FA 11 DB $11 01FB 8C DB $8C 01FC C8 DB $C8 ; *14* (C8->48) 01FD 62 DB $62 01FE 55 DB $55 01FF 20 DB $20 0200 E1 DB $E1 0201 70 DB $70 0202 8E DB $8E 0203 DA DB $DA 0204 A3 DB $A3 0205 7A DB $7A 0206 5F DB $5F 0207 9F DB $9F 0208 5F DB $5F 0209 CC DB $CC 020A 2A DB $2A 020B 28 DB $28 020C 08 DB $08 020D 0B DB $0B 020E 62 DB $62 020F C8 DB $C8 ; *15* (C8->48) 0210 E5 DB $E5 0211 FF DB $FF 0212 FF DB $FF 0213 59 DB $59 0214 F7 DB $F7 0215 07 DB $07 0216 A5 DB $A5 0217 70 DB $70 0218 B6 DB $B6 0219 D1 DB $D1 021A 13 DB $13 021B D1 DB $D1 021C C8 DB $C8 ; *16* (C8->48) 021D 02 DB $02 021E 02 DB $02 021F 01 DB $01 0220 88 DB $88 0221 37 DB $37 0222 07 DB $07 0223 2E DB $2E 0224 90 DB $90 0225 3F DB $3F 0226 A5 DB $A5 0227 8B DB $8B 0228 BF DB $BF 0229 02 DB $02 022A F9 DB $F9 022B FF DB $FF 022C FF DB $FF 022D 02 DB $02 022E 02 DB $02 022F 08 DB $08 0230 D1 DB $D1 0231 CA DB $CA ; *17* (CA->4A) 0232 76 DB $76 0233 90 DB $90 0234 ED DB $ED 0235 9A DB $9A 0236 2E DB $2E 0237 E8 DB $E8 0238 07 DB $07 0239 09 DB $09 023A CC DB $CC 023B C9 DB $C9 ; *18* (C9->49) 023C 7B DB $7B 023D 86 DB $86 023E 78 DB $78 023F 92 DB $92 0240 EB DB $EB 0241 9F DB $9F 0242 27 DB $27 0243 FC DB $FC 0244 0B DB $0B 0245 AC DB $AC 0246 C8 DB $C8 ; *19* (C8->48) 0247 22 DB $22 0248 0B DB $0B 0249 F3 DB $F3 024A FC DB $FC 024B FF DB $FF 024C FA DB $FA 024D FF DB $FF 024E C7 DB $C7 024F FF DB $FF 0250 1C DB $1C 0251 03 DB $03 0252 BB DB $BB 0253 CD DB $CD ; *20* (CD->4D) 0254 B4 DB $B4 0255 F6 DB $F6 0256 10 DB $10 0257 2A DB $2A 0258 C8 DB $C8 ; *21* (C8->48) 0259 C6 DB $C6 025A 54 DB $54 025B 03 DB $03 025C FD DB $FD 025D 72 DB $72 025E 38 DB $38 025F F5 DB $F5 0260 DC DB $DC 0261 7B DB $7B 0262 30 DB $30 0263 02 DB $02 0264 F8 DB $F8 0265 32 DB $32 0266 A6 DB $A6 0267 26 DB $26 0268 0C DB $0C 0269 66 DB $66 026A C8 DB $C8 ; *22* (C8->48) 026B 28 DB $28 026C FC DB $FC 026D BB DB $BB 026E FF DB $FF 026F DE DB $DE 0270 FB DB $FB 0271 E4 DB $E4 0272 BA DB $BA 0273 08 DB $08 0274 FA DB $FA 0275 07 DB $07 0276 01 DB $01 0277 46 DB $46 0278 CF DB $CF ; *23* (CF->4F) 0279 01 DB $01 027A 46 DB $46 027B CE DB $CE ; *24* (CE->4E) 027C 05 DB $05 027D CC DB $CC 027E CA DB $CA ; *25* (CA->4A) 027F FF DB $FF 0280 FA DB $FA 0281 7E DB $7E 0282 45 DB $45 0283 01 DB $01 0284 46 DB $46 0285 CC DB $CC ; *26* (CC->4C) 0286 01 DB $01 0287 46 DB $46 0288 CB DB $CB ; *27* (CB->4B) 0289 0C DB $0C 028A 91 DB $91 028B C8 DB $C8 ; *28* (C8->48) 028C B6 DB $B6 028D FD DB $FD 028E E1 DB $E1 028F 9B DB $9B 0290 7E DB $7E 0291 85 DB $85 0292 FD DB $FD 0293 FF DB $FF 0294 61 DB $61 0295 79 DB $79 0296 2D DB $2D 0297 0A DB $0A 0298 24 DB $24 0299 C9 DB $C9 ; *29* (C9->49) 029A 6A DB $6A 029B FC DB $FC 029C 57 DB $57 029D EC DB $EC 029E F5 DB $F5 029F FB DB $FB 02A0 08 DB $08 02A1 56 DB $56 02A2 AB DB $AB 02A3 02 DB $02 02A4 CC DB $CC 02A5 CB DB $CB ; *30* (CB->4B) 02A6 BF DB $BF 02A7 04 DB $04 02A8 ED DB $ED 02A9 CA DB $CA ; *31* (CA->4A) 02AA E1 DB $E1 02AB BF DB $BF 02AC DD DB $DD 02AD 03 DB $03 02AE D1 DB $D1 02AF CB DB $CB ; *32* (CB->4B) 02B0 95 DB $95 02B1 29 DB $29 02B2 01 DB $01 02B3 E6 DB $E6 02B4 C8 DB $C8 02B5 0D DB $0D 02B6 C3 DB $C3 02B7 C8 DB $C8 ; *33* (C8->48) 02B8 CD DB $CD 02B9 62 DB $62 02BA F3 DB $F3 02BB 5A DB $5A 02BC E3 DB $E3 02BD FF DB $FF 02BE A1 DB $A1 02BF 40 DB $40 02C0 1E DB $1E 02C1 4A DB $4A 02C2 02 DB $02 02C3 59 DB $59 02C4 0D DB $0D 02C5 8F DB $8F 02C6 CA DB $CA ; *34* (CA->4A) 02C7 FC DB $FC 02C8 02 DB $02 02C9 97 DB $97 02CA 9B DB $9B 02CB 08 DB $08 02CC 02 DB $02 02CD 09 DB $09 02CE F5 DB $F5 02CF 09 DB $09 02D0 2A DB $2A 02D1 62 DB $62 02D2 BB DB $BB 02D3 01 DB $01 02D4 E6 DB $E6 02D5 C8 DB $C8 02D6 04 DB $04 02D7 F0 DB $F0 02D8 CA DB $CA ; *35* (CA->4A) 02D9 F8 DB $F8 02DA DD DB $DD 02DB A8 DB $A8 02DC 02 DB $02 02DD C3 DB $C3 02DE C9 DB $C9 ; *36* (C9->49) 02DF 7F DB $7F 02E0 14 DB $14 02E1 94 DB $94 02E2 C8 DB $C8 ; *37* (C8->48) !! 02E3 02 DB $02 02E4 5C DB $5C 02E5 FB DB $FB 02E6 A0 DB $A0 02E7 FF DB $FF 02E8 22 DB $22 02E9 02 DB $02 02EA 52 DB $52 02EB A9 DB $A9 02EC 02 DB $02 02ED 19 DB $19 02EE 09 DB $09 02EF 4D DB $4D 02F0 A7 DB $A7 02F1 09 DB $09 02F2 ED DB $ED 02F3 AA DB $AA 02F4 02 DB $02 02F5 5C DB $5C 02F6 0C DB $0C 02F7 43 DB $43 02F8 C8 DB $C8 ; *38* (C8->48) 02F9 B5 DB $B5 02FA EA DB $EA 02FB 3F DB $3F 02FC E3 DB $E3 02FD BA DB $BA 02FE 40 DB $40 02FF C2 DB $C2 0300 FF DB $FF 0301 FF DB $FF 0302 11 DB $11 0303 FF DB $FF 0304 07 DB $07 0305 43 DB $43 0306 C9 DB $C9 ; *39* (C9->49) 0307 E4 DB $E4 0308 9A DB $9A 0309 84 DB $84 030A AA DB $AA 030B 7F DB $7F 030C 02 DB $02 030D 07 DB $07 030E ED DB $ED 030F C9 DB $C9 ; *40* (C9->49) 0310 FA DB $FA 0311 7E DB $7E 0312 BF DB $BF 0313 FF DB $FF 0314 FF DB $FF 0315 45 DB $45 0316 17 DB $17 0317 26 DB $26 0318 C8 DB $C8 ; *41* (C8->48) !! 0319 D4 DB $D4 031A 98 DB $98 031B 02 DB $02 031C 1C DB $1C 031D 02 DB $02 031E DC DB $DC 031F 02 DB $02 0320 1C DB $1C 0321 02 DB $02 0322 52 DB $52 0323 FD DB $FD 0324 20 DB $20 0325 FD DB $FD 0326 8C DB $8C 0327 02 DB $02 0328 1C DB $1C 0329 DF DB $DF 032A 02 DB $02 032B 1C DB $1C 032C 06 DB $06 032D ED DB $ED 032E 11 DB $11 032F 2A DB $2A 0330 28 DB $28 0331 C8 DB $C8 ; *42* (C8->48) !! 0332 6A DB $6A 0333 02 DB $02 0334 1C DB $1C 0335 02 DB $02 0336 3C DB $3C 0337 9F DB $9F 0338 02 DB $02 0339 1C DB $1C 033A 02 DB $02 033B 3C DB $3C 033C 05 DB $05 033D 99 DB $99 033E 02 DB $02 033F 1C DB $1C 0340 02 DB $02 0341 3C DB $3C 0342 05 DB $05 0343 0A DB $0A 0344 8E DB $8E 0345 02 DB $02 0346 1C DB $1C 0347 02 DB $02 0348 42 DB $42 0349 B9 DB $B9 034A 02 DB $02 034B 1C DB $1C 034C 9F DB $9F 034D 02 DB $02 034E 3C DB $3C 034F 02 DB $02 0350 1C DB $1C 0351 9F DB $9F 0352 02 DB $02 0353 3C DB $3C 0354 02 DB $02 0355 1C DB $1C 0356 9F DB $9F 0357 02 DB $02 0358 3C DB $3C 0359 02 DB $02 035A 1C DB $1C 035B 01 DB $01 035C E6 DB $E6 035D C8 DB $C8 035E 17 DB $17 035F 8D DB $8D 0360 C8 DB $C8 ; *43* (C8->48) !! 0361 26 DB $26 0362 02 DB $02 0363 31 DB $31 0364 03 DB $03 0365 38 DB $38 0366 66 DB $66 0367 6D DB $6D 0368 91 DB $91 0369 6D DB $6D 036A 2D DB $2D 036B 63 DB $63 036C 06 DB $06 036D 02 DB $02 036E 63 DB $63 036F D1 DB $D1 0370 06 DB $06 0371 F8 DB $F8 0372 FF DB $FF 0373 9F DB $9F 0374 46 DB $46 0375 02 DB $02 0376 15 DB $15 0377 06 DB $06 0378 25 DB $25 0379 C8 DB $C8 ; *44* (C8->48) 037A BE DB $BE 037B 43 DB $43 037C FF DB $FF 037D FB DB $FB 037E C0 DB $C0 037F 08 DB $08 0380 E9 DB $E9 0381 C9 DB $C9 ; *45* (C9->49) 0382 3C DB $3C 0383 02 DB $02 0384 3D DB $3D 0385 E1 DB $E1 0386 DD DB $DD 0387 9D DB $9D 0388 83 DB $83 0389 29 DB $29 038A E6 DB $E6 038B C8 DB $C8 ; *46* (C8->48) !! 038C 01 DB $01 038D 5F DB $5F 038E 9D DB $9D 038F 01 DB $01 0390 07 DB $07 0391 37 DB $37 0392 1F DB $1F 0393 9D DB $9D 0394 01 DB $01 0395 1D DB $1D 0396 01 DB $01 0397 1D DB $1D 0398 01 DB $01 0399 1F DB $1F 039A 9E DB $9E 039B 01 DB $01 039C 1C DB $1C 039D 01 DB $01 039E 1C DB $1C 039F 01 DB $01 03A0 9D DB $9D 03A1 01 DB $01 03A2 5D DB $5D 03A3 01 DB $01 03A4 20 DB $20 03A5 7C DB $7C 03A6 01 DB $01 03A7 3E DB $3E 03A8 01 DB $01 03A9 1C DB $1C 03AA 01 DB $01 03AB 20 DB $20 03AC 27 DB $27 03AD 54 DB $54 03AE 01 DB $01 03AF 5D DB $5D 03B0 01 DB $01 03B1 20 DB $20 03B2 7C DB $7C 03B3 01 DB $01 03B4 01 DB $01 03B5 45 DB $45 03B6 C8 DB $C8 ; *47* (C8->48) 03B7 C3 DB $C3 03B8 01 DB $01 03B9 87 DB $87 03BA C8 DB $C8 ; *48* (C8->48) 03BB 03 DB $03 03BC 01 DB $01 03BD 87 DB $87 03BE C9 DB $C9 ; *49* (C9->49) 03BF 01 DB $01 03C0 01 DB $01 03C1 68 DB $68 03C2 CE DB $CE ; *50* (CE->4E) 03C3 E0 DB $E0 03C4 01 DB $01 03C5 67 DB $67 03C6 CF DB $CF ; *51* (CF->4F) 03C7 07 DB $07 03C8 0A DB $0A 03C9 03 DB $03 03CA D9 DB $D9 ; *52* (D9->59) BLUE CROWN 03CB 01 DB $01 03CC 02 DB $02 03CD 27 DB $27 03CE D9 DB $D9 ; *53* (D9->59) YELLOW EYE 03CF 35 DB $35 03D0 01 DB $01 03D1 47 DB $47 03D2 D9 DB $D9 ; *54* (D9->59) RED MOUTH 03D3 15 DB $15 03D4 04 DB $04 03D5 48 DB $48 03D6 D9 DB $D9 ; *55* (D9->59) RED TONGUE 03D7 02 DB $02 03D8 01 DB $01 03D9 8B DB $8B 03DA D9 DB $D9 ; *56* (D9->59) 03DB 03 DB $03 03DC 01 DB $01 03DD AB DB $AB 03DE D9 DB $D9 ; *57* (D9->59) 03DF 03 DB $03 03E0 07 DB $07 03E1 0E DB $0E 03E2 15 DB $15 03E3 1C DB $1C 03E4 23 DB $23 03E5 2A DB $2A 03E6 31 DB $31 03E7 38 DB $38 ; ################ END OF GRAPHIC BLOCK ################ 03E8 3EFE LD A,$FE ; SUBROUTINE USED BY THE TAPE LOADING ROUTINE 03EA 110020 LD DE,$2000 03ED 14 INC D 03EE 08 EX AF,AF' 03EF 15 DEC D 03F0 3E4F LD A,$4F 03F2 D3FE OUT ($FE),A 03F4 DBFE IN A,($FE) 03F6 1F RRA 03F7 E620 AND $20 03F9 F602 OR $02 03FB 4F LD C,A 03FC BF CP A 03FD C0 RET NZ 03FE CD7904 CALL $0479 ; ---@@@(11)0400:04->14 0401 30FA JR NC,$03FD 0403 211504 LD HL,$0415 0406 10FE DJNZ $0406 0408 2B DEC HL 0409 7C LD A,H 040A B5 OR L 040B 20F9 JR NZ,$0406 040D CD7504 CALL $0475 ; ---@@@(12)040F:04->14 0410 30EB JR NC,$03FD 0412 069C LD B,$9C 0414 CD7504 CALL $0475 ; ---@@@(13)0416:04->14 0417 30E4 JR NC,$03FD 0419 3EC6 LD A,$C6 041B B8 CP B 041C 30E0 JR NC,$03FE 041E 24 INC H 041F 20F1 JR NZ,$0412 0421 06C9 LD B,$C9 0423 CD7904 CALL $0479 ; ---@@@(14)0425:04->14 0426 30D5 JR NC,$03FD 0428 78 LD A,B 0429 FED4 CP $D4 042B 30F4 JR NC,$0421 042D CD7904 CALL $0479 ; ---@@@(15)042F:04->14 0430 D0 RET NC 0431 79 LD A,C 0432 EE03 XOR $03 0434 4F LD C,A 0435 2600 LD H,$00 0437 06B0 LD B,$B0 0439 181F JR $045A 043B 08 EX AF,AF' 043C 2007 JR NZ,$0445 043E 300F JR NC,$044F 0440 DD7500 LD (IX+$00),L 0443 180F JR $0454 0445 CB11 RL C 0447 AD XOR L 0448 C0 RET NZ 0449 79 LD A,C 044A 1F RRA 044B 4F LD C,A 044C 13 INC DE 044D 1807 JR $0456 044F DD7E00 LD A,(IX+$00) 0452 AD XOR L 0453 C0 RET NZ 0454 DD23 INC IX 0456 1B DEC DE 0457 08 EX AF,AF' 0458 06B2 LD B,$B2 045A 2E01 LD L,$01 045C CD7504 CALL $0475 ; ---@@@(16)045E:04->14 045F D0 RET NC 0460 3ECB LD A,$CB 0462 B8 CP B 0463 CB15 RL L 0465 06B0 LD B,$B0 0467 D25C04 JP NC,$045C ; ---@@@(17)0469:04->14 046A 7C LD A,H 046B AD XOR L 046C 67 LD H,A 046D 7A LD A,D 046E B3 OR E 046F 20CA JR NZ,$043B 0471 7C LD A,H 0472 FE01 CP $01 0474 C9 RET ; END SUBROUTINE USED BY TAPE LOADING ROUTINE 0475 CD7904 CALL $0479 ; SUBROUTINE USED BY THE ABOVE ---@@@(18)0477:04->14 0478 D0 RET NC 0479 3E16 LD A,$16 047B 3D DEC A 047C 20FD JR NZ,$047B 047E A7 AND A 047F 04 INC B 0480 C8 RET Z 0481 3E7F LD A,$7F 0483 DBFE IN A,($FE) 0485 1F RRA 0486 D0 RET NC 0487 A9 XOR C 0488 E620 AND $20 048A 28F3 JR Z,$047F 048C 79 LD A,C 048D 2F CPL 048E 4F LD C,A 048F E607 AND $07 0491 F648 OR $48 0493 D3FE OUT ($FE),A 0495 37 SCF 0496 C9 RET ; END SUBROUTINE USED BY THE ABOVE 0497 3E01 LD A,$01 ; ############## START CHECKSUM ROUTINE ################ 0499 D3FE OUT ($FE),A ; set "O6" to 0, CPU access to DRAM#1 instead of VRAM 049B 21AF04 LD HL,$04AF ; address of code block below ---@@@(19)049D:04->14 049E 1100E0 LD DE,$E000 ; beginning of upper half of DRAM#1 (6000 in BASIC config) 04A1 011700 LD BC,$0017 04A4 EDB0 LDIR ; copy code block to beginning of upper half of DRAM#1 04A6 3E41 LD A,$41 04A8 D3FE OUT ($FE),A ; set "O6" to 1, CPU access to VRAM instead of DRAM#1 04AA 210060 LD HL,$6000 04AD 181A JR $04C9 ; ######## code block ######## ; this block is copied to E000h, and after loading OPUS (BASIC clears the memory) ; will be available at 6000h. If then run (using the command ; "E 6000" in monitor mode) it will save the OPUS code in two 8KB blocks. 04AF DD210000 LD IX,$0000 04B3 DDE5 PUSH IX ; 0000 is the return addr after calling this routine (reset OPUS) 04B5 CD0D60 CALL $600D ; this calls the entry point below 04B8 DD210020 LD IX,$2000 04BC 110020 LD DE,$2000 ; entry point (6000 in BASIC/OPUS config) 04BF 3EFE LD A,$FE 04C1 37 SCF 04C2 CDC204 CALL $04C2 ; start of SAVE routine in BASIC (also exactly THIS address !!) 04C5 C9 RET ; ######## end code block ######### 04C6 210000 LD HL,$0000 04C9 E5 PUSH HL 04CA 0608 LD B,$08 ; loop counter 04CC 210040 LD HL,$4000 04CF FD21F007 LD IY,$07F0 ; start of BASIC LOAD code and also BASIC checksum data ---@@@(20)04D2:07->17 04D3 DD218CDA LD IX,$DA8C ; addr of color attr for color pattern under logo (within video mem) 04D7 DDCB00FE SET 7,(IX+$00) ; set BLINK attribute for first cell of color pattern <--- <--| 04DB C5 PUSH BC ; | 04DC 110008 LD DE,$0800 ; | 04DF D9 EXX ; | 04E0 210000 LD HL,$0000 ; | 04E3 D9 EXX ; | 04E4 7E LD A,(HL) ; <--- <--- <--- <--- <--- <--- | read from (4000) | 04E5 D9 EXX ; | | 04E6 0608 LD B,$08 ; loop counter | | 04E8 4F LD C,A ; | | 04E9 CB01 RLC C ; CY = bit 7<--- <--- <---| | | 04EB 9F SBC A,A ; A=00-CY | | | 04EC 5F LD E,A ; | | | 04ED 7D LD A,L ; (loop starts w HL=0000) | | | 04EE E640 AND $40 ; | | | 04F0 D601 SUB $01 ; | | | 04F2 9F SBC A,A ; | | | 04F3 AB XOR E ; | | | 04F4 5F LD E,A ; | | | 04F5 7C LD A,H ; | | | 04F6 E601 AND $01 ; | | | 04F8 D601 SUB $01 ; | | | 04FA 9F SBC A,A ; | | | 04FB AB XOR E ; | | | 04FC 5F LD E,A ; | | | 04FD 7C LD A,H ; | | | 04FE E608 AND $08 ; | | | 0500 D601 SUB $01 ; | | | 0502 9F SBC A,A ; | | | 0503 AB XOR E ; | | | 0504 5F LD E,A ; | | | 0505 7C LD A,H ; | | | 0506 E680 AND $80 ; | | | 0508 D601 SUB $01 ; | | | 050A 9F SBC A,A ; | | | 050B AB XOR E ; | | | 050C 07 RLCA ; | | | 050D CB15 RL L ; | | | 050F CB14 RL H ; | | | 0511 10D6 DJNZ $04E9 ; ---> 8 loops -----> --->| | | 0513 D9 EXX ; | | 0514 23 INC HL ; increment mem pointer | | 0515 1B DEC DE ; decrement loop counter | | 0516 7A LD A,D ;\ test if | | 0517 B3 OR E ;/ DE=0000 | | 0518 20CA JR NZ,$04E4 ; ---> ---> 800h loops---> ---> | | 051A D9 EXX ; | 051B FD5E00 LD E,(IY+$00) ; stored checksum lower 8 bits | 051E FD5601 LD D,(IY+$01) ; stored checksum upper 8 bits | 0521 FD23 INC IY ; increment checksum pointer | 0523 FD23 INC IY ; increment checksum pointer | 0525 AF XOR A ; reset CY flag | 0526 ED52 SBC HL,DE ; compare computed checksum with stored checksum | 0528 2004 JR NZ,$052E ; ---> ---> --->| | 052A DDCB00BE RES 7,(IX+$00) ; | if chksum ok, reset blinking on color pattern | 052E DD23 INC IX ; <--- <--- <---| point to next cell in color pattern | 0530 D9 EXX ; | 0531 C1 POP BC ; B = loop counter | 0532 10A3 DJNZ $04D7 ; ---> 8 loops -----> ---> ---> ---> ---> ---> ---> ---> ---> ->| 0534 E1 POP HL 0535 D9 EXX 0536 FF RST $38 ; ################## END CHECKSUM ROUTINE ########################## ---@@@(21)0536:FF->C7 (RST 0) ; ################## TAPE LOADING ROUTINE ########################## 0537 DD210080 LD IX,$8000 ; loading address of first half of BASIC 053B 37 SCF 053C CDE803 CALL $03E8 ; tape loading ---@@@(22)053E:03->13 053F 3008 JR NC,$0549 0541 DD2100A0 LD IX,$A000 0545 37 SCF 0546 CDE803 CALL $03E8 ; tape loading ---@@@(23)0548:03->13 0549 D20400 JP NC,$0004 ; ---@@@(24)054B:00->10 054C AF XOR A ; A = 00 054D 67 LD H,A ;\load HL register 054E 6F LD L,A ;/with 0000 value (start addr in upcoming BASIC config) 054F C35100 JP $0051 ; ################## END TAPE LOADING ROUTINE ###################### ---@@@(25)0551:00->10 ; ; ; ; ################## START CP/M LOADING ROUTINE #################### 0552 DBFD IN A,($FD) ; read 1 byte from 8272 Data Register, it should be 80 (result of the ; invalid command sent to 8272 by the instruction at 002A). 0554 FE80 CP $80 ; This tests whether 8272 present and properly reset. 0556 C20400 JP NZ,$0004 ; if not 80, restart execution from the beginning of the BOOT EPROM ---@@@(26)0558:00->10 0559 216105 LD HL,$0561 ; 0561 is the addr of the 3rd instruction after this one 055C 3E41 LD A,$41 ; "41" is to be written to 8255 Port C after next line is executed 055E C35100 JP $0051 ; (see comments for code at 0051) ---@@@(27)0560:00->10 ; ; after the jump, "41" is written to 8255 Port C which means: ; signal "O6" set to 1, "O5" set to 0, border color set to blue; ; then bit 7 of register R is reset to 0 by instruction "LD R,A" ; and configuration is changed to CP/M ("O6"=1). In this new config ; execution starts from address stored in register HL previously. ; The entire BOOT EPROM code was previously copied to beginning of DRAM#0 ; (see comments at 001D) and DRAM#0 is located at 0000 in CP/M config ; so HL points now to exactly the next instruction below. 0561 3E01 LD A,$01 0563 D3FE OUT ($FE),A ; write 01 to port C of 8255 which means: ; ; set border to blue, set signal "SO" to 0, "O5" to 0 (lower half ; of VRAM displayed), "O6" to 0 (CPU access to DRAM#1 instead of VRAM) 0565 210000 LD HL,$0000 ;\ 0568 1100F8 LD DE,$F800 ; | BOOT EPROM code is again relocated, this time 056B 010008 LD BC,$0800 ; | to F800-FFFF (top of RAM, end of DRAM#3) 056E EDB0 LDIR ;/ from this point on, addresses listed on the left side are actually added to F800 0570 C373FD JP $FD73 ; this jump continues execution with exactly the next line (0573+F800=FD73) 0573 ED5E IM 2 ; ******* NOTE: THIS IS THE STACK BASE SET AT THE BEGINNING OF THIS BOOT EPROM ********* 0575 21E8FF LD HL,$FFE8 ; CTC interrupt table start address 0578 7C LD A,H ; upper half of CTC interrupt table start address (FF)... 0579 ED47 LD I,A ; ...is stored in register I (see Z80 docs) 057B 7D LD A,L ; lower half of CTC interrupt table start address (E8)... 057C D3E3 OUT ($E3),A ; ... is sent to CTC channel 0 (Enable Interrupt, Counter Mode, Prescaler=256, ; Falling Edge, Pulse Trigger, No Time Const., Continue, Vector) ; MEANING: Interrupt Vector being used by all 4 channels!! ; Interrupt Vector = 11101cc0 where cc is the CTC channel. ; requesting the interrupt. So vector for CTC0 = E8, CTC1 = EA, CTC2 = EC, CTC3 = EE ; The upper half of addr table pointer is FF which means 07 within this BOOT EPROM. ; Thus the vector table is at 07E8 (byte read), 07EC (sector read) in this BOOT EPROM. 057E 3EFF LD A,$FF ; data for CTC0 on next line: set CTC0 to counter mode and enable CTC0 interrupts 0580 D3E3 OUT ($E3),A ; write FF to CTC channel 0 (Enable Interrupt, Counter Mode, Prescaler=256, ; Rising Edge, CLK/TRG Pulse Starts Timer, Time Const. Follows, Reset, Control). ; MEANING: Reset, Enable Interrupts for Channel 0, a Time Constant follows. 0582 3E01 LD A,$01 ; time constant for CTC0 on next line: generate INT for each byte transferred from 8272 to µP 0584 D3E3 OUT ($E3),A ; write 01 to CTC channel 0 ; MEANING: Time Constant byte (=01, for 1 byte read). 0586 21E4FF LD HL,$FFE4 ; address of the 2 args (6F, 01) of 8272 Specify command (for DD) on next line ; These args specify Head Load/Unload times, Step Rate and choose Non-DMA mode, ; (SRT=10 ms, HUT=240 ms, HLT=0 ms, Non-DMA) 0589 CD0BFF CALL $FF0B ; call CTC1+2_INIT (which also sends a Specify command) 058C 0604 LD B,$04 ; B as counter, 4 = nr of times to repeat the cycle below, for 4 possible FDDs 058E C5 PUSH BC ; <--- <--- <--- <--- <--- <--- <--- <--- <--- <--- <--- <--- <--- <----| 058F 010402 LD BC,$0204 ; Code for Sense Drive Status cmd (04) with 1 arg (B=02) | 0592 CDBDFE CALL $FEBD ; call 8272_CMD (run Sense Drive Status cmd to check if 8272 is ready) | 0595 CDF9FE CALL $FEF9 ; call 8272_READ (read command result into (FFD5)) | 0598 C1 POP BC ; | 0599 3AD5FF LD A,($FFD5); actual addr 07D5 in this BOOT EPROM (Sense Dr Stat result) | 059C CB6F BIT 5,A ; test bit 5 of it (READY) | 059E 2016 JR NZ,$05B6 ; if bit 5 not zero (drive is READY), jump ahead to 05B6 ---> ---> ---> | ---> ->(FF95 has the nr. 05A0 2195FF LD HL,$FF95 ; address of a data byte actually located at 0795 in this BOOT EPROM | |of first drive 05A3 34 INC (HL) ; increment data byte (arg for Sense Drive Stat, increment drive no#) | |found ready) 05A4 10E8 DJNZ $058E ; ---> ---> ---> ---> repeat cycle 4 times for all 4 drives --> ---> ---> | ; if no FDD responding properly, switch back to startup cfg | 05A6 F3 DI ; ################ CPM_TO_COBRA ################## | 05A7 ED46 IM 0 ; | 05A9 AF XOR A ; | 05AA ED47 LD I,A ; | 05AC 210400 LD HL,$0004 ; | ---@@@(28)05AE:00->10 05AF 3EC1 LD A,$C1 ; | 05B1 D3FE OUT ($FE),A ; write C1 to port C of 8255 which means: | ; set "SO" to 1, "O6" to 1, "O5" to 0, border color to blue | 05B3 ED4F LD R,A ; set bit 7 of R to 1 ---> hardware config changes to startup config | 05B5 E9 JP (HL) ; jump address in the new config (beginning of this BOOT EPROM) | ; | ; ############# begin actual CP/M loading <--- <--- <--- <--- <--- <--- <--- <--| 05B6 010702 LD BC,$0207 ; 02 means 1 argument, 07 = opcode for 8272 Recalibrate command 05B9 CDBDFE CALL $FEBD ; call 8272_CMD (send Recalibrate cmd to 8272 w.arg at FF95) 05BC CD40FF CALL $FF40 ; call 8272_SEEK_TEST (Sense Interrupt Status) 05BF CD31FF CALL $FF31 ; call 8272_COND_SEEK (Seek track #2 + Sense Interrupt Status) 05C2 014A02 LD BC,$024A ; 02 means 1 argument, 4A = opcode for 8272 Read ID command (in Double Density) 05C5 CDBDFE CALL $FEBD ; call 8272_CMD (send Read ID command in DD to 8272) 05C8 CDF9FE CALL $FEF9 ; call 8272_READ (read command result into (FFD5-FFDB)) 05CB 3AD5FF LD A,($FFD5); load first result byte of Read ID into register A 05CE E6C0 AND $C0 ; testing bits 6 and 7 05D0 2811 JR Z,$05E3 ; if they are 0 (no errors in DD), jump 7 lines below ---> ---> ---> ----> 05D2 21ACFF LD HL,$FFAC ; > if errors reading DD, FDD must be SD, copy SD params block from 07AC | 05D5 1199FF LD DE,$FF99 ; > over cmd params block at 0799 within this BOOT EPROM code | 05D8 010A00 LD BC,$000A ; > (to change future 8272 command params for Single Density). | 05DB EDB0 LDIR ; After this, (FF99)=02 means DD, 00 means SD (arg #5 of 8272 Read Data) | 05DD 21E6FF LD HL,$FFE6 ; addr of the 2 args (BF, 17) of Specify command (for SD) on next line | ; (SRT=5 ms, HUT=240 ms, HLT=22 ms, Non-DMA) | 05E0 CD0BFF CALL $FF0B ; call CTC1+2_INIT (which also sends a Specify command) | 05E3 3A99FF LD A,($FF99); <--- <--- <--- <--- <--- <--- <--- <--- <--- <--- <--- <--- <--- <-----| 05E6 B7 OR A ; test (FF99) if zero (initially 02, it is 02 if DD, 00 if SD) 05E7 0604 LD B,$04 ; B used as counter** if DD (read 4 sectors = 4 x 512 = 2048 bytes) 05E9 1E01 LD E,$01 ; index to locate in memory the byte for sector number to use next 05EB 2002 JR NZ,$05EF ; if not SD ---> --->| B=04, C=(FFE7)=17 (the 2nd arg of Specify at 05E0) 05ED 0610 LD B,$10 ; B used as counter** | if SD (read 16 sectors = 16 x 128 = 2048 bytes) 05EF CD54FF CALL $FF54 ; FDD_SECT_READ <-<---< read 1 sector to mem starting at (FFD0-FFD1)=F400 05F2 1C INC E ; next sector to try | E=1...4 for DD, E=1...10h for SD 05F3 10FA DJNZ $05EF ; ---> ---> ---> ---->| (FFA3-FFA6) for DD, (FFB6-FFC6) for SD 05F5 210000 LD HL,$0000 ; (sectors 1,5,9,4 if DD, 01,07,0D,13,19,05,0B,11,17,03,09,0F,15,02,08,0E if SD) 05F8 22D0FF LD ($FFD0),HL ; (FFD0)&(FFD1) = 0000 = new start address for storage of data read from disk 05FB 2100F4 LD HL,$F400 05FE E5 PUSH HL 05FF E1 POP HL ; <--- jump here from 067D <--- <--- <--- <--- <--- <--- <--- <--- <--- <--- <--- <--<--| 0600 0640 LD B,$40 ; 40h=64 directory entries to search (2048 bytes) | 0602 7E LD A,(HL) ; <--- <--- <--- <--- <--- <--- <--- <--| search max 64 (40h) times | 0603 B7 OR A ; | in steps of 32 (20h) bytes (=1 dir entry) | 0604 2014 JR NZ,$061A ; ---> ---> ---> ------> not 00 ? | for a 00 byte (meaning USER 0) in data read | 0606 C5 PUSH BC ; * 40xx | | from FDD. If no 00 byte found after 64 tries, | 0607 E5 PUSH HL ; **F400+(20*count) | | reset BOOT EPROM | 0608 110900 LD DE,$0009 ; | | If 00 byte found, go 9 bytes after it and | 060B 19 ADD HL,DE ; HL=F409+(20*count) | | test to see if the 3 next bytes (filename | 060C EB EX DE,HL ; HL=0009, DE=F409+... | | extension) contain "SYS" in their lower 7 bits| 060D 21DEFF LD HL,$FFDE ; HL=FFDE | | If they do, then continue executing code after| 0610 0603 LD B,$03 ; 3 chars of a fname ext| to check | this loop. If they are not, reset BOOT EPROM | 0612 1A LD A,(DE) ; A=(F409) <--- <--- <- | <-----| | | 0613 E67F AND $7F ; | | | | 0615 BE CP (HL) ; cmp sect w signature | (SYS) | | | 0616 280A JR Z,$0622 ; ---> ---> ---> | | | | 0618 E1 POP HL ; ** | | | | | 0619 C1 POP BC ; * | | | | | 061A 112000 LD DE,$0020 ; <--- <--- <-- | <-----| | | | 061D 19 ADD HL,DE ; fwd 20 bytes | | | | 061E 10E2 DJNZ $0602 ; ---> ---> --->|---> ---> ---> ---> ---> | 0620 1884 JR $05A6 ; CPM_TO_COBRA | | | 0622 13 INC DE ; <--- <--- <---| | | 0623 23 INC HL ; | | 0624 10EC DJNZ $0612 ; ---> ---> ---> ---> ---> ---->| | 0626 D1 POP DE ; **DE=F400 | 0627 211000 LD HL,$0010 ; If "S", "Y", "S" or D3, D9, D3 found, go 16 | 062A 19 ADD HL,DE ; HL=F410 (10h) bytes after the 00 previously found | 062B 1100FC LD DE,$FC00 ; DE=FC00 before "SYS" and copy 16 (10h) bytes to FC00 | 062E D5 PUSH DE ; (SP)=FC00 These bytes are the allocation table for the | 062F 011000 LD BC,$0010 ; current directory entry | 0632 EDB0 LDIR ; 16 bytes from F410 to FC00. After this, HL=F420, DE=FC10 | 0634 E3 EX (SP),HL ; (SP)=F420=addr of next entry, HL=FC00=addr of allocation table | 0635 7E LD A,(HL) ; low byte of block address (07) for CHRIS.SYS or Kryss.SYS | 0636 E5 PUSH HL ; (SP)=FC00 <--- <--- <--- <--- <--- <--- <--- <--- <--- <---- <--- <--- <------| | 0637 2600 LD H,$00 ; | | 0639 6F LD L,A ; low byte of block address (07) for CHRIS.SYS or Kryss.SYS | | 063A 01FF03 LD BC,$03FF ; repeat next loop 3 times, C=FF | | 063D CB25 SLA L ; <--- <---| assume SD (8 sectors/block) and compute absolute sector addr | | <-- Block size is assumed to be 1K but for DD it is actually 2K. 063F CB14 RL H ; HL=HL*2 | as (block_addr*8) and adjust later (/4) if DD (2 sectors/block) | | The trick is that the block number used is mangled to give 0641 10FA DJNZ $063D ; ---> --->| (00111000=38h) | | the correct target sector on current DD disks 0643 23 INC HL ; HL=block addr*8+1=sect_addr_SD (sector numbers start at 1) (00111001=39h) | | 0644 ED5B9FFF LD DE,($FF9F) ; 256B Sectors/cyl=36 (24h) if DD, 128B Sectors/cyl=26 (1Ah) if SD | | <-- DD sector size used here 0648 0C INC C ; C = 00 for start <--- <--- <--- <--- <-- | | is different than real size (512B) 0649 ED52 SBC HL,DE ; (sect_addr_SD) minus (sectors/cyl) | | | used on today's CoBra disks 064B 30FB JR NC,$0648 ; ---> ---> ---> ---> ---> ---> ---> --->| | | (this code is old & translation 064D 19 ADD HL,DE ; >> HL=(sect_addr_SD) mod (sect/cyl)=sect#_on_cyl_SD (0015 if DD, 0005 if SD) | | algorithm was not updated, instead ; ; and C=(sect_addr_SD)/(sect/cyl)=cyl# (01 if DD or 02 if SD) | | the computing of data location was 064E 3A99FF LD A,($FF99); arg #4 of 8272 command (N=log2(bytes/sector)-log2(128)) | | just mangled to give correct result) 0651 B7 OR A ; test if 00 (Single Density) | | 0652 0608 LD B,$08 ; 8 loops if SD | | 0654 2808 JR Z,$065E ; if Single Density (L=05) ---->| | | 0656 0602 LD B,$02 ; 2 loops if DD | adjust sect#_on_cyl for Double Density | | 0658 2D DEC L ; ] L=L-1 | x MOD y = x - y * int(x/y) = expr | | 0659 CB3D SRL L ; ] L=L/2 | then expr/4 = x/4 - y/4 * int(x/y) so here | | 065B CB3D SRL L ; ] L=L/2 | (adr*8) mod 36=adr*8-36*[(adr*8)/36]=expr | | 065D 2C INC L ; ] L=(sect#_on_cyl-1)/4+1=06 | and expr/4=adr*2-9*[(adr*2)/9]=(adr*2) mod 9 | | 065E 3E02 LD A,$02 ; <--- <--- <--- <--- <--- <----| so dividing by 4 gives the correct adjustment | | 0660 81 ADD A,C ; cyl# + 2 because block numbers start on cyl #2 (03 if DD or 04 if SD) | | 0661 57 LD D,A ; track# = 03 or 04 (DD or SD) | | 0662 5D LD E,L ; sect# = 06 or 05 (DD or SD) | | 0663 7A LD A,D ; <--- <--- 2 loops if DD, 8 loops if SD <--- <--- <--- <---| | | read from disk to mem starting at 0000 0664 32D4FF LD ($FFD4),A; (FFD4)=track number in 8272_COND_SEEK | 03...04 (if DD) | | if DD read trk#3 sect#3 and trk#4 sect#7 0667 CD54FF CALL $FF54 ; call FDD_SECT_READ E=06,07 -->sect 3,7 | | | 066A 2A9AFF LD HL,($FF9A) ; L=final sector nr on a track (EOT), arg #6 of 8272 cmd | | | 066D 23 INC HL ; L=0A or 1B | | | 066E 1C INC E ; used as index to determine sector no. | 06...07 | | 066F 7B LD A,E ; | | | 0670 BD CP L ; comp index w max. sector no | | | 0671 3803 JR C,$0676 ; --> --->| | | | 0673 14 INC D ; | | 04...0B (if DD) | | 0674 1E01 LD E,$01 ; | | | | 0676 10EB DJNZ $0663 ; ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> --->| | | 0678 E1 POP HL ; FC00 | | 0679 23 INC HL ; FC01 | | 067A 3E0F LD A,$0F ; | | 067C A5 AND L ; 01 | | 067D 2880 JR Z,$05FF ; no jump most likely --> ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> --->| 067F 7E LD A,(HL) ; (FC01)=00 most likely | 0680 B7 OR A ; | 0681 20B3 JR NZ,$0636 ; no jump most likely ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> ---->| 0683 F3 DI 0684 210000 LD HL,$0000 0687 7E LD A,(HL) 0688 FEF3 CP $F3 ; test if first byte of presumed CP/M loader code is F3 (should be 00) 068A D9 EXX 068B 214300 LD HL,$0043 068E CAAFFD JP Z,$FDAF ; if it is, go to CPM_TO_COBRA 0691 D9 EXX 0692 E9 JP (HL) ; ########## End of actual CP/M loading ########### 0693 08 EX AF,AF' ; ############## CTC0 (Byte Read) Interrupt Service Routine #################### 0694 3E7F LD A,$7F ; control word for CTC channel 1 (in next instruction) 0696 D3EB OUT ($EB),A ; write 7F to CTC channel 1 (Disable Interrupt, Counter Mode, Prescaler=256, ; Rising Edge, Pulse Trigger, Time Const. Follows, Reset, Control) ; MEANING: Reset Channel 1, resume operation after loading a time constant. 0698 3A9EFF LD A,($FF9E); load A with data byte from address 079E (00) 069B D3EB OUT ($EB),A ; write time constant byte (00) to CTC channel 1 069D 08 EX AF,AF' 069E FB EI ; --------- CTC Channel 1 & 3 Interrupt service routine (does nothing) --------- 069F ED4D RETI ; ############################################################################## 06A1 EDA2 INI ; ############## Alternate CTC0 (Byte Read) Interrupt Service Routine ########## 06A3 FB EI ; 06A4 ED4D RETI ; ; ############## CTC2 (Sector Read) Interrupt Service Routine ################## 06A6 22D2FF LD ($FFD2),HL ; HL contains the addr of the last byte read from disk by 8272_CMD1 plus 1 06A9 2193FE LD HL,$FE93 ; FE93 is the initial CTC0 interrupt routine address stored at FFE8 06AC 22E8FF LD ($FFE8),HL ; restore initial CTC0 interrupt routine address stored at FFE8 06AF 0E00 LD C,$00 ; C was used to store the port address for 8272 Data Register (FD) 06B1 FB EI ; 06B2 ED4D RETI ; ; ##################### 8272_POLL ############################## 06B4 DBF5 IN A,($F5) ; read 8272 Status Register | this routine polls the 8272 Status Register 06B6 CB7F BIT 7,A ; test bit 7 (RQM) | until 8272 is ready to send or receive 06B8 28FA JR Z,$06B4 ; if bit 7 = 0 read 8272 Status Register again | data to or from the CPU. When ready (RQM=1) 06BA CB77 BIT 6,A ; test bit 6 | bit 6 is tested (DIO, 0=send/1=receive) 06BC C9 RET ; ; ##################### 8272_CMD ############################### 06BD 2195FF LD HL,$FF95 ; (command args addr=0795) 06C0 CDB4FE CALL $FEB4 ; call 8272_POLL ------ 8272_CMD_HL -------- <--- <--- <--- <---| 06C3 C2A6FD JP NZ,$FDA6 ; jump to CPM_TO_COBRA, if data out of 8272 | 06C6 79 LD A,C ; (C = opcode for 8272 command) | 06C7 D3FD OUT ($FD),A ; send opcode to 8272 Data Register | 06C9 4E LD C,(HL) ; load C with command arg from address (HL) | 06CA 23 INC HL ; increment pointer to command args | 06CB 10F3 DJNZ $06C0 ; ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> 06CD C9 RET ; ##################### 8272_CMD1 ############################## 06CE 1195FF LD DE,$FF95 ; start address for 8272 command arguments 06D1 21A1FE LD HL,$FEA1 ; address of another interrupt routine (06A1 in the BOOT EPROM) 06D4 22E8FF LD ($FFE8),HL ; replace the CTC0 interrupt routine address in address table 06D7 2AD0FF LD HL,($FFD0) ; initially (FFD0)=00, (FFD1)=F4, so HL=F400 06DA 1803 JR $06DF ; ---> --->| 06DC 1A LD A,(DE) ; <--- <-- | <--- <--- <--- <--- <--- <--- <----| 06DD 13 INC DE ; V | 06DE 4F LD C,A ; |save A in C bcoz A used by 8272_POLL| 06DF CDB4FE CALL $FEB4 ; <--- <---| 8272_POLL | 06E2 C2A6FD JP NZ,$FDA6 ; if not ready for new command, CPM_TO_COBRA | 06E5 79 LD A,C ; | 06E6 0EFD LD C,$FD ; | 06E8 ED79 OUT (C),A ; send contents of A to 8272 Data Register | 06EA 10F0 DJNZ $06DC ; ---> ---> ---> ---> ---> ---> ---> ---> ---->| ; ; At this point, B=00, C=FD, HL=F400. The next instruction halts the CPU, waiting ; for an interrupt from 8272 after each byte was read from disk. ; The interrupt routine at FEA1 then writes the I/O bytes from (C=FD) to memory starting at (HL) ; which is F400. HL is a memory pointer and B is a counter for this process (00-FF). ; (B decremented & HL incremented by the INI instruction in the CTC0 alternate int. routine) 06EC 76 HALT ; wait for next interrupt <--- <--- <--- <---| 06ED DBF5 IN A,($F5) ; read 8272 Status Register | 06EF E620 AND $20 ; test bit 5 (Non-DMA Execution Phase) | 06F1 20F9 JR NZ,$06EC ; if "1" (Execution not finished) ---> ----->| 06F3 2193FE LD HL,$FE93 ; initial address of the CTC0 interrupt routine in the interrupt addr table 06F6 22E8FF LD ($FFE8),HL ; restore initial address of the CTC0 interrupt routine in the interrupt addr table 06F9 21D5FF LD HL,$FFD5 ; ##################### 8272_READ ############################### 06FC 0608 LD B,$08 ; ### reads max 8 bytes from 8272 into memory at FFD5 ### 06FE CDB4FE CALL $FEB4 ; 8272_POLL <---- <---- <---- <---- <---- <---- <---- <---- <---| 0701 C8 RET Z ; return if data to go from CPU into 8272 (normal return) | 0702 DBFD IN A,($FD) ; read from 8272 Data Register | 0704 77 LD (HL),A ; store data at address pointed to by HL | 0705 23 INC HL ; increment pointer | 0706 10F6 DJNZ $06FE ; if B not zero ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> 0708 C3A6FD JP $FDA6 ; ---> CPM_TO_COBRA 070B F3 DI ; ##################### CTC1+2_INIT ########################### 070C 3E7F LD A,$7F ; control word for CTC channel 1 (in next instruction) 070E D3EB OUT ($EB),A ; write 7F to CTC channel 1 (Disable Interrupt, Counter Mode, Presc=256, ; Rising Edge, Pulse Trigger, Time Const. Follows, Reset, Control) ; MEANING: Reset Channel 1, resume operation after loading a time const. 0710 3A9EFF LD A,($FF9E); load A with data byte from address 079E (00) 0713 D3EB OUT ($EB),A ; write time constant byte (00) to CTC channel 1 0715 3EFF LD A,$FF ; control word for CTC channel 2 (in next instruction) 0717 D3F3 OUT ($F3),A ; write FF to CTC channel 2 (Enable Interrupt, Counter Mode, Prescaler=256, ; Rising Edge, Pulse Trigger, Time Const. Follows, Reset, Control) ; MEANING: Reset Channel 2, resume operation after loading a time constant. 0719 3A9DFF LD A,($FF9D); load A with data byte from address 079D (02) 071C D3F3 OUT ($F3),A ; write time constant byte (02) to CTC channel 2 071E FB EI ; 071F 010303 LD BC,$0303 ; B=nr of args for 8272 command + 1, C=opcode for 8272 "Specify" command 0722 189C JR $06C0 ; ---> ---> jump to 8272_CMD_HL ---> ---> ; ##################### 8272_CMD_SIS ########################## 0724 010801 LD BC,$0108 ; 01 means no arguments (zero), 08 = opcode for 8272 Sense Interrupt Status 0727 CDBDFE CALL $FEBD ; call 8272_CMD, send Sense Interrupt Status command to 8272 072A CDF9FE CALL $FEF9 ; call 8272_READ, read command result (2 bytes) into memory at FFD5-FFD6 072D 3AD5FF LD A,($FFD5); load command result byte 1 (ST0) into register A 0730 C9 RET ; ##################### 8272_COND_SEEK ######################## 0731 3AD4FF LD A,($FFD4); \ Compare (FFD4) (initially 02) - (FFD4)=track to seek 0734 2196FF LD HL,$FF96 ; \ with (FF96) (initially 00) - (FF96)=current track 0737 BE CP (HL) ; / and 0738 C8 RET Z ; / return if equal 0739 77 LD (HL),A ; replace (FF96) with (FFD4) 073A 010F03 LD BC,$030F ; Seek command for 8272, with 2 arguments (drive, cyl=2), to be sent in next instruction 073D CDBDFE CALL $FEBD ; call 8272_CMD ; --------------------- 8272_SEEK_TEST ------------------------ 0740 CD24FF CALL $FF24 ; call 8272_CMD_SIS and get result in A ; (*** Sense Interrupt Status is mandatory after Seek or Recalibrate ***) 0743 CB6F BIT 5,A ; test bit 5 (Seek End) 0745 28F9 JR Z,$0740 ; if Seek not finished, go back 2 lines above (??? should it be 4 lines ???) 0747 E6D8 AND $D8 ; check if errors or drive not ready 0749 C2A6FD JP NZ,$FDA6 ; ---> if so, jump to CPM_TO_COBRA 074C CD24FF CALL $FF24 ; 8272_CMD_SIS - send Sense Interrupt Status command to 8272 and get result in A <-- 074F FE80 CP $80 ; check if Invalid Command Issue | 0751 C8 RET Z ; return if so | 0752 18F8 JR $074C ; go back 3 lines above ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> --->| ; ##################### FDD_SECT_READ ############################### 0754 C5 PUSH BC ; 0417 > BC and DE are saved on stack so their contents 0755 D5 PUSH DE ; 0001 > can be restored at the end of this routine 0756 CD31FF CALL $FF31 ; call 8272_COND_SEEK 0759 1600 LD D,$00 ; 075B 2AA1FF LD HL,($FFA1) ; (FFA1)=A2, (FFA2)=FF for DD or (FFA1)=B5, (FFA2)=FF for SD 075E 19 ADD HL,DE ; result HL=FFA2+0001=FFA3 for DD or HL=FFB5+0001=FFB6 for SD 075F 7E LD A,(HL) ; (FFA3)=01 (for DD) or (FFB5)=01 (for SD) 0760 3298FF LD ($FF98),A; (0798) is arg #4 of Read Data (Sector number) 0763 060A LD B,$0A ; 10 loops to do next ; 0765 C5 PUSH BC ; BC=0A17 (B used as counter**) <--- <--- <--- <--- <--- <--- <--- <---| 0766 3A99FF LD A,($FF99); (FF99)=02 or 00 | 0769 B7 OR A ; (FF99) can be either 02 (initial val) or 00 if Read ID at 05C5 gave errors (see lines 05D2-05DB) 076A 010609 LD BC,$0906 ; 06 = opcode for 8272 Read Data command with 8 args starting at FF95 (Single Density, MFM=0) 076D 2802 JR Z,$0771 ; skip next line if A=00 (Read Data in Single Density) | 076F CBF1 SET 6,C ; BC=0946 meaning 8272 Read Data command with 8 args starting at FF95 | bit 6 is MFM bit, MFM=1 means ; ; 46 = opcode for <Read Data - MT=0 (single side), MFM=1 (DD), no Skip> | Read Data in Double Density ; **arguments: - Side 0 drive found Ready | ; ---> @FF96 >> - Cyl 00 (C=00) | ; - Head 00 (H=00) | ; ---> @FF98 >> - Sector Number 01 (R=01) | ; ---> @FF99 >> - 512 bytes/sector (N=02) or 128 if N=00 (Singl Density)| ; - EOT=09 (End Of Track Sector Number) | <-- 09 if DD, 1A if SD ; - GPL=2A (Gap 3 Length) | <-- 2A if DD, 07 if SD ; - DTL=FF (Data Length, has no meaning for N != 00) | <-- FF if DD, 80 if SD 0771 CDCEFE CALL $FECE ; call 8272_CMD1, run Read Data command | <-- data being read is saved at address stored in (FFD0-FFD1) 0774 AF XOR A ; A=0 ; | 0775 B1 OR C ; C=00 after 8272_CMD1 (CTC2 interrupt sets C to 00) | 0776 C1 POP BC ; BC=0A17 (B used as counter**) | 0777 200E JR NZ,$0787 ; if C not zero, jump ---> ---> ---> -->| | 0779 21D7FF LD HL,$FFD7 ; (FFD7)=ST2 (result byte #3) | | 077C 7E LD A,(HL) ; | | 077D 2B DEC HL ; (FFD6)=ST1 (result byte #2) | | 077E B6 OR (HL) ; | | 077F 2006 JR NZ,$0787 ; if errors ST1 or ST0 != 00 ---> ----->| | 0781 2B DEC HL ; (FFD5)=ST0 (result byte #1) | | 0782 7E LD A,(HL) ; | | 0783 E6D8 AND $D8 ; check if err or drv not Ready | | 0785 2805 JR Z,$078C ; if no error, jump ---> ---> --->| | | 0787 10DC DJNZ $0765 ; ---> ---> ---> ---> ---> ---> ---> -->| -----> ---> ---> ---> ---> ---> 0789 C3A6FD JP $FDA6 ; CPM_TO_COBRA | ; | 078C 2AD2FF LD HL,($FFD2) ; <--- <--- <--- <--- <--- <----| CTC2 int. routine saved addr for next sector into (FFD2),(FFD3) 078F 22D0FF LD ($FFD0),HL ; update start mem address for next sector read from FDD 0792 D1 POP DE ; > restore BC and DE to the values they had 0793 C1 POP BC ; > before execution of this routine 0794 C9 RET ; #################### END CP/M LOADING ROUTINE #################### ; ; ############## BEGIN OF DATA BLOCK ################ 0795 00 DB $00 ;\ <<<--- arg #1 of max. 8 (Side and drive number) 0796 00 DB $00 ; | <<<--- arg #2 of 8272 Read Data (current track number) 0797 00 DB $00 ; | <<<--- arg #3 of 8272 Read Data (head selected) 0798 01 DB $01 ; | <<<--- arg #4 of 8272 Read Data (Sector number) 0799 02 DB $02 ;*| <<<--- arg #5 of 8272 Read Data (N=02, Double Density) * 079A 09 DB $09 ; | <<<--- arg #6 of 8272 Read Data (EOT, final sector nr on track) | 079B 2A DB $2A ; | <<<--- arg #7 | Double Density 079C FF DB $FF ;/ <<<--- arg #8 | 079D 02 DB $02 ; CTC Channel 2 Time Constant - for Double Density \ 2 x 256 = 512 | parameters 079E 00 DB $00 ; CTC Channel 1 Time Constant - for Double Density / (DD sector size) | 079F 24 DB $24 ; <<<--- No of sectors per cylinder in Double Density | block 07A0 00 DB $00 ; | 07A1 A2 DB $A2 ; <<<---| base pointer to beginning of translation table | 07A2 FF DB $FF ;* <<<---| with DD sector numbers (next 9 bytes) * 07A3 01 DB $01 ; N 07A4 05 DB $05 ; N 07A5 09 DB $09 ; N 9 sector numbers (01...09) 07A6 04 DB $04 ; N to try with 07A7 08 DB $08 ; N the Read Data 07A8 03 DB $03 ; N command if 07A9 07 DB $07 ; N Double Density 07AA 02 DB $02 ; N 07AB 06 DB $06 ; N 07AC 00 DB $00 ;*| <<<--- arg #5 of 8272 Read Data (N=00, Single Density) * 07AD 1A DB $1A ; | <<<--- arg #6 of 8272 Read Data (EOT, final sector nr on track) | 07AE 07 DB $07 ; | <<<--- arg #7 | Single Density 07AF 80 DB $80 ;/ <<<--- arg #8 | 07B0 01 DB $01 ; CTC Channel 2 Time Constant - for Single Density \ 1 x 128 = 128 | parameters 07B1 80 DB $80 ; CTC Channel 1 Time Constant - for Single Density / (SD sector size) | 07B2 1A DB $1A ; <<<--- No of sectors per cylinder in Single Density | block 07B3 00 DB $00 ; | 07B4 B5 DB $B5 ; <<<---| base pointer to beginning of translation table | 07B5 FF DB $FF ;* <<<---| with SD sector numbers (next 26 bytes) * 07B6 01 DB $01 ; N 07B7 07 DB $07 ; N 07B8 0D DB $0D ; N 07B9 13 DB $13 ; N 07BA 19 DB $19 ; N 07BB 05 DB $05 ; N 07BC 0B DB $0B ; N 07BD 11 DB $11 ; N 07BE 17 DB $17 ; N 07BF 03 DB $03 ; N 07C0 09 DB $09 ; N 07C1 0F DB $0F ; N 26 sector numbers (01...1A) 07C2 15 DB $15 ; N to try with 07C3 02 DB $02 ; N the Read Data 07C4 08 DB $08 ; N command if 07C5 0E DB $0E ; N Single Density 07C6 14 DB $14 ; N 07C7 1A DB $1A ; N 07C8 06 DB $06 ; N 07C9 0C DB $0C ; N 07CA 12 DB $12 ; N 07CB 18 DB $18 ; N 07CC 04 DB $04 ; N 07CD 0A DB $0A ; N 07CE 10 DB $10 ; N 07CF 16 DB $16 ; N 07D0 00 DB $00 ; \these 2 bytes contain the start address for last sector 07D1 F4 DB $F4 ; /read from floppy disk (F400) used by 8272_CMD1 07D2 00 DB $00 ; \these 2 bytes contain the start address for next sector 07D3 F4 DB $F4 ; /to be read from floppy disk (see CTC2 Int. Routine & end of FDD_SECT_READ) 07D4 02 DB $02 ; <<<--- track to seek in next command 07D5 41 DB $41 ; A \ storage area 07D6 52 DB $52 ; R | for result data 07D7 4D DB $4D ; M | from 8272_READ 07D8 41 DB $41 ; A | (7 bytes) 07D9 26 DB $26 ; & | 07DA 24 DB $24 ; $ | 07DB 4F DB $4F ; O / 07DC 46 DB $46 ; F 07DD 54 DB $54 ; T 07DE 53 DB $53 ; S 07DF 59 DB $59 ; Y 07E0 53 DB $53 ; S 07E1 38 DB $38 ; 8 07E2 30 DB $30 ; 0 07E3 6B DB $6B ; k 07E4 6F DB $6F ; o \ arguments for a "Specify" command: Step Rate Time = B (5 ms), 07E5 01 DB $01 ; / Head Unload Time = F (240 ms), Head Load Time = 0B (22 ms), Non-DMA 07E6 BF DB $BF ;\ arguments for a "Specify" command: Step Rate Time = B (5 ms), 07E7 17 DB $17 ;/ Head Unload Time = F (240 ms), Head Load Time = 0B (22 ms), Non-DMA 07E8 93 DB $93 ;\ interrupt routine address = FE93 (0693 within this BOOT EPROM) 07E9 FE DB $FE ;/ for CTC Channel 0 (Byte Read) 07EA 9E DB $9E ;\ interrupt routine address = FE9E (069E within this BOOT EPROM) 07EB FE DB $FE ;/ for CTC Channel 1 (Not used) 07EC A6 DB $A6 ;\ interrupt routine address = FEA6 (06A6 within this BOOT EPROM) 07ED FE DB $FE ;/ for CTC Channel 2 (Sector Read) 07EE 9E DB $9E ;\ interrupt routine address = FE9E (069E within this BOOT EPROM) 07EF FE DB $FE ;/ for CTC Channel 3 (Not used) ; ; ################ END OF DATA BLOCK ################ ; ; ################ START OF BASIC LOADING ROUTINE ################# 07F0 3E0F LD A,$0F ; control word to be written to 8255 meaning "set bit 7 of Port C" 07F2 D3DF OUT ($DF),A ; which is signal "SO" which drives pin A14 of BASIC EPROM (>= 32K) ; that means the BASIC EPROM must have BASIC code at 4000 (or C000) ; ################ START OF OPUS LOADING ROUTINE ################## 07F4 210000 LD HL,$0000 ; jump address after hardware configuration change 07F7 D9 EXX 07F8 FF RST $38 ; jump to the BASIC CONFIGURATION ROUTINE ---@@@(29)07F8:FF->C3 07F9 FF RST 38 ; ---@@@(30)07F9:FF->38 07FA FF RST 38 ; ---@@@(31)07FA:FF->10 07FB FF RST 38 07FC FF RST 38 07FD FF RST 38 07FE FF RST 38 07FF FF RST 38